#include "client.h"

int main(int argc, char *argv[]){
	struct sockaddr_in serv_addr, data_addr;
	char buf[STR_BUF_SZ],*p,hostname[HOSTNAME_LEN]={0};
	volatile int cmd;

	if(argc != 2){
		printf("Usage: %s <host>[:<port>]\n", argv[0]);
		exit(1);
	}

	//系统检测，64位
	system_detect();

	//注册终端结束符Ctrl+C
	key_control_c_register();

	serv_sock=socket(AF_INET, SOCK_STREAM, 0);
	if(serv_sock == -1){
		socket_error();
	}

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	//判断是否为域名
	strcpy(hostname, strtok(argv[1], ":"));
	if(is_domain_name(hostname)){
		struct hostent *host;
		host=gethostbyname(hostname);
		if(!host){
			fprintf(stderr, "Domain parse error.");
			return 1;
		}
		bzero(&hostname, HOSTNAME_LEN);
		sprintf(hostname, "%s", inet_ntoa(*((struct in_addr *)host->h_addr_list[0])));
	}
	serv_addr.sin_addr.s_addr = inet_addr(hostname);
	//默认1956端口
	if((p=strtok(NULL, ":")) != NULL){
		serv_addr.sin_port = htons(atoi(p));
	}else{
		serv_addr.sin_port = htons(1956);
	}
	if(connect(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1){
		connect_error();
	}

	printf("connected to %s at %d successful.\n", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
	puts("empire ftp server 1.0.");
	if(!access_auth()){
		close(serv_sock);
		puts("authenticated failed.");
		exit(1);
	}
	authed = true;
	puts("using binary mode to transfer files.");
	printf("commands available: %s \n", privs);
	load_user_privs();

	while(true){
		char fabspath[ABS_PATH_LEN]={0};
		printf("ftp>");
		bzero(&buf, STR_BUF_SZ);
		fgets(buf, STR_BUF_SZ, stdin);

		//解析命令 读取第一个命令
		cmd = cmd_parse(buf);
		if(DEBUG){
			printf("Command %d \n", cmd);
		}
		if(cmd == CMD_NOT_FOUND){
			puts("command not found.");
		}else if(cmd == CMD_ENTER){
			continue;
		}else if(cmd == CMD_TWO_LONG){
			puts("command two long.");
		}else if(cmd == CMD_LOCAL){//执行本地命令
			int ch;
			FILE *fp;

			if ((fp = popen(buf+1*sizeof(char), "r")) != NULL) {
				while((ch=fgetc(fp)) != EOF){
					fputc(ch, stdout);
				}
				pclose(fp);
			}
			continue;
		}else{//发往服务器
			//检测能否使用该权限命令
			if(!is_allowed_priv(cmd)){
				puts("Permission denied.");
				continue;
			}
			//判断服务器是否已经断开连接
			if(!server_alive_query()){
				puts("Remote host has closed the current connection.");
				break;
			}

			//put命令先进行本地文件的读权限检查
			if(cmd == CMD_PUT){
				char temp[3], filepath[PATH_LEN]={0};

				sscanf(buf, "%s%s", temp, filepath);
				get_file_abs_path(filepath, fabspath);
				if(is_dir(fabspath) || !is_readable(fabspath)){
					continue;
				}
			}

			cmd_rebuild(cmd, STAT_CREADY, buf);
			if(DEBUG){
				printf("After rebuild: %s \n", buf);
			}
			write(serv_sock, buf, STR_BUF_SZ);

			if(cmd == CMD_BYE){
				quit_request();
				break;
			}
		}

		if(cmd == CMD_LS){
			int len, ch, state, total=0;
			FILE *lsfp=fdopen(dup(serv_sock), "r");
			bzero(&buf, STR_BUF_SZ);
			//读取返回结果
			while(fread((void *)buf, 1, STR_BUF_SZ, lsfp) > 0){
				len=strlen(buf);
				total += len;
				if(DEBUG){
					printf("Recieved %d bytes.\n", len);
				}
				printf("%s", buf);
				bzero(&buf, STR_BUF_SZ);
				if(len < STR_BUF_SZ){
					break;
				}
			}
			if(DEBUG){
				printf("Total Recieve %d bytes. \n", total);
			}
			bzero(&buf, STR_BUF_SZ);
			fread((void *)buf, 1, STR_BUF_SZ, lsfp);
			sscanf(buf, "%d", &state);
			printf("%d Send directory OK.\n", state);
			fclose(lsfp);
		}else if(cmd == CMD_PWD){
			bzero(&buf, STR_BUF_SZ);
			//fread((void *)buf, 1, STR_BUF_SZ, rfp);
			read(serv_sock, buf, STR_BUF_SZ);
			printf("Current workpath: %s \n", buf);
		}else if(cmd == CMD_CD){
			FILE *cdfp=fdopen(dup(serv_sock), "r");
			bzero(&buf, STR_BUF_SZ);
			fread((void *)buf, 1, STR_BUF_SZ, cdfp);

			char result[STR_BUF_SZ];
			int state;
			sscanf(buf, "%4d%s", &state, result);
			if(state == STAT_F_OK){
				printf("%d Directory successfully changed.\n", state);
				printf("Current directory: %s\n", result);
			}else{
				printf("%d Failed to change directory.\n", state);
			}
			fclose(cdfp);
		}else if(cmd == CMD_GET){
			int state,len,total=0;
			char result[STR_BUF_SZ],filename[PATH_LEN];

			bzero(&buf, STR_BUF_SZ);
//			fread(buf, 1, STR_BUF_SZ, rfp);
			read(serv_sock, buf, STR_BUF_SZ);
			sscanf(buf, "%d%s", &state, result);
			if(state == STAT_F_R){
				strcpy(filename, result);
				bzero(&buf, STR_BUF_SZ);
				bzero(&result, STR_BUF_SZ);
				//检查当前目录是否可写
				shell_exec("pwd", result);
				if(!is_writable(result)){
					sprintf(buf, "%-4d%-4d%s", CMD_GET, STAT_F_NW, "current directory is not writable.");
					write(serv_sock, buf, STR_BUF_SZ);
					continue;
				}
				//cmd state startlen filename
				sprintf(buf, "%-4d%-4d%-10d%s", CMD_GET, STAT_F_W, 0, filename);
				write(serv_sock, buf, STR_BUF_SZ);
				bzero(&buf, STR_BUF_SZ);
//				fread(buf, 1, STR_BUF_SZ, rfp);
				read(serv_sock, buf, STR_BUF_SZ);
				sscanf(buf, "%d%s", &state, result);
				//返回请求的文件状态： 是否可读
				puts(buf);
				if(state == STAT_F_OK){
					bzero(&buf, STR_BUF_SZ);
					FILE *fp=fopen(filename, "w");
					FILE *rfp=fdopen(dup(serv_sock), "r");
					while(fscanf(rfp, "%3X", &len) > 0){
						fread(buf, 1, STR_BUF_SZ, rfp);
						fwrite(buf, 1, len, fp);
						bzero(&buf, STR_BUF_SZ);
						total += len;
						if(DEBUG){
							printf("Received %d Bytes. \n", len);
						}
						if(ferror(rfp)  || feof(rfp) || len < STR_BUF_SZ){
							break;
						}
					}
					puts("Download complete.");
					if(DEBUG){
						printf("Total Received %d Bytes. \n", total);
					}
					fflush(fp);
					fclose(fp);
					fclose(rfp);
				}
			}
		}else if(cmd == CMD_PUT){//上载文件
			int state, len;
			char filename[PATH_LEN]={0},fbuf[STR_BUF_SZ-HEADER_LEN];
			FILE *fp;

			bzero(&buf, STR_BUF_SZ);
//			fread(buf, 1, STR_BUF_SZ, rfp);
			read(serv_sock, buf, STR_BUF_SZ);
			sscanf(buf, "%d", &state);
			if(state == STAT_F_W){
				int total=0;
				//传送本地文件名
				get_file_rel_name(fabspath, filename);
				if((fp=fopen(fabspath, "rb")) != NULL){
					bzero(&fbuf, STR_BUF_SZ);
					FILE *wfp=fdopen(dup(serv_sock), "w");
					while((len=fread(fbuf, 1, UPLOAD_LEN, fp)) >0){
						fprintf(wfp, "%-*d%-*d%-*d%-*d%-*s", CMD_LEN, CMD_PUT, STATE_LEN,
								STAT_F_OK, START_LEN, total, SEND_LEN, len, FNAME_LEN, filename);
						fwrite(fbuf, 1, UPLOAD_LEN, wfp);
						bzero(&fbuf, UPLOAD_LEN);
						total += len;
						printf("Writes Total %d Bytes. \n", total);
						if(ferror(fp) || feof(fp)){
							break;
						}
					}
					if(DEBUG){
						printf("Writes Total %d Bytes. \n", total);
					}
					puts("Upload complete.");
					fflush(wfp);
					fclose(wfp);
					fclose(fp);
				}
			}
		}else if(cmd == CMD_HELP){//返回权限信息
			int state;
			bzero(&buf, STR_BUF_SZ);
			//fread(buf, 1, STR_BUF_SZ, rfp);
			read(serv_sock, buf, STR_BUF_SZ);
			puts(buf);
		}
	}

	client_resource_revoke();

	return 0;
}
